package com.csii.adhoc.util;


import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @description: List转树形工具类
 * @author: panChuanJiang
 * @create: 2021-02-01 10:44
 */
public final class TreeUtils<T> {
    /**
     * 默认ID字段
     */
    private static final String DEFAULT_ID = "menuId";
    /**
     * 默认父级id字段
     */
    private static final String DEFAULT_PARENT_ID = "parentId";
    /**
     * 默认子级 集合字段
     */
    private static final String DEFAULT_CHILDREN = "children";
    /**
     * 顶级节点的 父级id
     */
    private static final String TOP_PARENT_ID = "0";

    /**
     * 都采用默认配置 构建树形结构
     *
     * @param list
     * @return
     */
    public static <T> List<T> createTree(List<T> list) {
        return createTree(list, DEFAULT_ID, DEFAULT_PARENT_ID, DEFAULT_CHILDREN);
    }

    /**
     * 只有 实体主键不同 构建树形结构
     *
     * @param list
     * @param idName
     * @return
     */
    public static <T> List<T> createTree(List<T> list, String idName) {
        return createTree(list, idName, DEFAULT_PARENT_ID, DEFAULT_CHILDREN);
    }

    /**
     * 只有 实体主键不同 构建树形结构
     *
     * @param list
     * @param idName
     * @return
     */
    public static <T> List<T> createTree(List<T> list, String idName, String topParentId) {
        return createTree(list, idName, DEFAULT_PARENT_ID, DEFAULT_CHILDREN, topParentId);
    }

    /**
     * 构建树形结构数据
     *
     * @param list      要转换的集合
     * @param idName    实体id字段名
     * @param pIdName   实体父级id字段名
     * @param childName 实体子集集合字段名
     * @return
     */
    public static <T> List<T> createTree(List<T> list, String idName, String pIdName, String childName) {
        return createTree(list, idName, pIdName, childName, TOP_PARENT_ID);
    }

    /**
     * 构建树形结构数据
     *
     * @param list        要转换的集合
     * @param idName      实体id字段名
     * @param pIdName     实体父级id字段名
     * @param childName   实体子集集合字段名
     * @param topParentId 顶层父类id
     * @return
     */
    public static <T> List<T> createTree(List<T> list, String idName, String pIdName, String childName, String topParentId) {
        List<T> result = new ArrayList<T>();
        try {
            for (T t : list) {
                Class<?> aClass = t.getClass();
                Field parentId = aClass.getDeclaredField(pIdName);
                parentId.setAccessible(true);
                Object o = parentId.get(t);
                if (topParentId == null) {
                    if (o == null){
                        result.add(t);
                    }
                } else {
                    if (String.valueOf(o).equals(topParentId)) {
                        result.add(t);
                    }
                }
            }
            for (T parent : result) {
                recursiveTree(parent, list, idName, pIdName, childName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    private static <T> T recursiveTree(T parent, List<T> list, String idName, String pIdName, String childName) throws Exception {
        List<T> children = new ArrayList<T>();
        Class<?> pClass = parent.getClass();
        Field id = pClass.getDeclaredField(idName);
        id.setAccessible(true);
        Object o = id.get(parent);
        for (T t : list) {
            Class<?> aClass = t.getClass();
            Field parentId = aClass.getDeclaredField(pIdName);
            parentId.setAccessible(true);
            Object o1 = parentId.get(t);
            if (String.valueOf(o).equals(String.valueOf(o1))) {
                t = recursiveTree(t, list, idName, pIdName, childName);
                children.add(t);
            }
        }
        Field child = pClass.getDeclaredField(childName);
        child.setAccessible(true);
        child.set(parent, children);
        return parent;
    }

    /**
     * 树形数据转回List
     *
     * @param list      要转换的集合
     * @param childName 实体子集集合字段名
     * @return
     */
    public static <T> List<T> treeToList(List<T> list, String childName) {
        if (ParamCheckUtils.checkListIsEmpty(list)) {
            return new ArrayList<>();
        }
        List<T> res = new ArrayList<>();
        list.forEach(item -> {
            res.add(item);
            Class<?> childrenClass = item.getClass();
            Field children = null;
            try {
                children = childrenClass.getDeclaredField(childName);
                children.setAccessible(true);
                Object obj = children.get(item);
                if (obj != null) {
                    List<T> childrens = (List<T>) obj;
                    if (childrens.size() > 0) {
                        res.addAll(treeToList(childrens, childName));
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        return res;
    }

    /**
     * 树形数据转回List
     *
     * @param list 要转换的集合
     * @return
     */
    public static <T> List<T> treeToListNow(List<T> list) {
        Integer parentIdInteger = 0;
        return treeToListReal(list, parentIdInteger);
    }

    private static <T> List<T> treeToListReal(List<T> list, Integer parentId) {
        if (ParamCheckUtils.checkListIsEmpty(list)) {
            return new ArrayList<>();
        }
        List<T> res = new ArrayList<>();
        int size = list.size();

        for (int i = 0; i < size; i++) {
            T item = list.get(i);
            Class<?> childrenClass = item.getClass();
            Field children = null;
            try {
                children = childrenClass.getDeclaredField(DEFAULT_CHILDREN);
                children.setAccessible(true);
                Object obj = children.get(item);
                // 先设置 parentId
                Field parentIdField = childrenClass.getDeclaredField(DEFAULT_PARENT_ID);
                parentIdField.setAccessible(true);
                parentIdField.set(item, "" + parentId);
                // 先设置 menuId
                Field idField = childrenClass.getDeclaredField(DEFAULT_ID);
                idField.setAccessible(true);
                // 同批次循环 menuId +1
                int childIdNow = parentId + 1 + i;
                idField.set(item, "" + childIdNow);
                res.add(item);
                if (obj != null) {
                    List<T> childrens = (List<T>) obj;
                    if (childrens.size() > 0) {
                        res.addAll(treeToListReal(childrens, childIdNow));
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return res;
    }

    public static <T> List<T> getSon(List<T> list, Object pId) {
        // 子菜单
        List<T> childList = new ArrayList<T>();
        for (T t : list) {
            Class<?> aClass = t.getClass();
            Field pIdField = null;
            try {
                pIdField = aClass.getDeclaredField(DEFAULT_PARENT_ID);
                pIdField.setAccessible(true);
                Object object = pIdField.get(t);
                if (object == null) {
                    continue;
                }
                if (String.valueOf(object).equals(String.valueOf(pId))) {
                    childList.add(t);
                }
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }

        }
        return childList;
    }

    /**
     * 集合转树形结构方法
     *
     * @param parentId  父级id
     * @param list      要转换的集合
     * @param idName    实体id字段名
     * @param pIdName   实体父级id字段名
     * @param childName 实体子集集合字段名
     * @return
     * @throws Exception
     */
    public static <
            T> List<T> getChild(Object parentId, List<T> list, String idName, String pIdName, String childName) throws
            Exception {
        // 子菜单
        List<T> childList = new ArrayList<T>();
        for (T t : list) {
            Class<?> aClass = t.getClass();
            Field pId = aClass.getDeclaredField(pIdName);
            pId.setAccessible(true);
            Object o = pId.get(t);
            if (o == null) {
                continue;
            }
            if (String.valueOf(o).equals(String.valueOf(parentId))) {
                childList.add(t);
            }
        }
        // 把子菜单的子菜单再循环一遍
        for (T t : childList) {
            Class<?> aClass = t.getClass();
            Field pId = aClass.getDeclaredField(idName);
            pId.setAccessible(true);
            Object o = pId.get(t);
            List<T> childLis = getChild(String.valueOf(o), list, idName, pIdName, childName);
            Field child = aClass.getDeclaredField(childName);
            child.setAccessible(true);
            child.set(t, childLis);
        }
        // 判断递归结束
        if (childList.size() == 0) {
            return null;
        }
        return childList;
    }


}
